/**
 * \file vmunit.h
 **/

#ifndef R_VMUNIT_H
#define R_VMUNIT_H

#include "standard.h"

/**
 * \brief "Unit" is the most basic element of a VM binary. It is a 32-bit value
 * that can represent an instruction, or an argument to an instruction:
 * anything from an address in the segment, symbol table index, register...
 *
 * We call the leftmost 4 bits of a Unit its type. The remaining 28 bits
 * are termed the "body".
 **/
typedef uint32_t RUnit;

/**
 * \brief Masks that separate the type and the body.
 **/
#define R_UNIT_TYPE_MASK     ((uint32_t) 0xF0000000)
#define R_UNIT_BODY_MASK     ((uint32_t) 0x0FFFFFFF)

/**
 * \brief This RUnit is an instruction (body defines which).
 **/
#define R_UNIT_INSTRUCTION   ((uint32_t) 0x00000000)

/**
 * \brief This RUnit is an address (body defines where in the segment).
 **/
#define R_UNIT_ADDRESS       ((uint32_t) 0x10000000)

/**
 * \brief A direct value (body defines the index in the direct value table).
 **/
#define R_UNIT_DIRECT_VALUE  ((uint32_t) 0x20000000)

/**
 * \brief A symbol (body is the index in the symbol table).
 **/
#define R_UNIT_SYMBOL        ((uint32_t) 0x30000000)

/**
 * \brief A local symbol.
 **/
#define R_UNIT_LOCAL_SYMBOL  ((uint32_t) 0x40000000)

/**
 * \brief A global symbol.
 **/
#define R_UNIT_GLOBAL_SYMBOL ((uint32_t) 0x50000000)

/**
 * \brief A register specifier (body defines index of the register).
 **/
#define R_UNIT_REGISTER      ((uint32_t) 0x60000000)

/**
 * \brief Return the type of the RUnit (one of R_UNIT_* constants).
 **/
#define r_unit_type(unit)    ((unit) & R_UNIT_TYPE_MASK)

/**
 * \brief Return the body of the RUnit.
 **/
#define r_unit_body(unit)    ((unit) & R_UNIT_BODY_MASK)

/**
 * \brief Clean RUnit constructors.
 **/
#define r_unit_new(type, body)  ((RUnit) ( \
                                  (((uint32_t) body) & R_UNIT_BODY_MASK) \
                                  | type))
#define r_unit_instruction(n)   r_unit_new(R_UNIT_INSTRUCTION, n)
#define r_unit_address(n)       r_unit_new(R_UNIT_ADDRESS, n)
#define r_unit_direct_value(n)  r_unit_new(R_UNIT_DIRECT_VALUE, n)
#define r_unit_symbol(n)        r_unit_new(R_UNIT_SYMBOL, n)
#define r_unit_local_symbol(n)  r_unit_new(R_UNIT_LOCAL_SYMBOL, n)
#define r_unit_global_symbol(n) r_unit_new(R_UNIT_GLOBAL_SYMBOL, n)
#define r_unit_register(n)      r_unit_new(R_UNIT_REGISTER, n)

/**
 * \brief This instruction assigns the value of operand2 to operand1.
 **/
#define R_VM_ASSIGN     0

/**
 * \brief This instruction calls the function given in operand1, passing
 * remaining operands as arguments.
 **/
#define R_VM_CALL       1


#endif /* R_VMUNIT_H */
